<template>
	<view class="container">
		<template v-for="formItem, formIndex of form">
			<template v-if="formItem.type !== 'hidden'">
				<!-- radio,checkbox单独处理 -->
				<view v-if="formItem.type === 'custom'" v-show="!formItem.hidden">
					<slot :name="`custom:${formIndex}`" :item="formItem"></slot>
				</view>
				<radio-group :id="`formItem_`+formItem.model" class="block form-item-wrapper" :class="formItem.groupCls"
					@change="radioChange(formItem, $event)" :key="`radio${formIndex}`"
					v-else-if="formItem.type === 'radio' && !formItem.hidden">
					<!-- 垂直排列 -->
					<template v-if="formItem.columnType === 'v'">
						<es-view class="cu-form-group" :class="formItem.wrapCls">
							<es-view class="title" :style="formItem.labelStyle" :cls="formItem.labelCls"
								v-if="formItem.showLabel">{{formItem.label}}
							</es-view>
						</es-view>
						<es-view class="cu-form-group" v-for="(radioItem, itemIndex) of formItem.items"
							:key="radioItem.value">
							<es-view class="title" :style="formItem.labelStyle" :cls="formItem.labelCls">{{radioItem.t}}
							</es-view>
							<!-- 自定义样式 -->
							<es-view style="position: relative;" :cls="formItem.wrapCls"
								:class="[formValue[formItem.model] === radioItem.v ? formItem.selCls : formItem.noSelCls, radioItem.d ? 'disabled' : '']"
								v-if="formItem.custom === true">
								<!-- <v-template :template="formItem.slot"></v-template> -->
								<!-- <radio class="hide-radio" :disabled="radioItem.d"
									:checked="formValue[formItem.model] === radioItem.v ?true:false" :value="radioItem.v">
								</radio> -->
								<slot :name="`radiocustom:${formIndex}`" :item="formItem"></slot>
							</es-view>

							<radio v-else :disabled="radioItem.d"
								:class="[formValue[formItem.model] === radioItem.v?'checked':''].concat(formItem.cls)"
								:checked="formValue[formItem.model] === radioItem.v ?true:false" :value="radioItem.v">
							</radio>
						</es-view>
					</template>
					<!-- 水平排列 -->
					<es-view class="cu-form-group radio-group-wrap" :cls="formItem.wrapCls" v-if="formItem.columnType === 'h'">
						<es-view class="title" :style="formItem.labelStyle" :cls="formItem.labelCls"
							v-if="formItem.showLabel">{{formItem.label}}
						</es-view>
						<view class="radio-item-wrap">
							<template v-for="radioItem of formItem.items">
								<es-view :cls="formItem.hCls" :key="radioItem.v">
									<!-- 自定义样式 -->
									<es-view style="position: relative;" :cls="formItem.wrapCls"
										:class="[formValue[formItem.model] === radioItem.v ? formItem.selCls : formItem.noSelCls, radioItem.d ? 'disabled' : '']"
										v-if="formItem.custom === true">
										<v-template :template="formItem.slot"></v-template>
										<radio :disabled="radioItem.d" class="hide-radio"
											:checked="formValue[formItem.model] === radioItem.v ?true:false"
											:value="radioItem.v"></radio>
										<view class="radio-item">
											<view class="icon-circle"
												:class="{ cur: formValue[formItem.model] === radioItem.v ?true:false }">
											</view><text class="radio-text">{{radioItem.t}}</text>
										</view>
									</es-view>

									<template v-else>
										<text>{{radioItem.t}}</text>
										<radio :disabled="radioItem.d"
											:class="[formValue[formItem.model] === radioItem.v?'checked':''].concat(formItem.cls)"
											:checked="formValue[formItem.model] === radioItem.v ?true:false"
											:value="radioItem.v"></radio>
									</template>
								</es-view>
							</template>
						</view>
						<view :id="`showError_${formItem.model}`" :class="{ hide: !formItem.error }" class="show-error flex align-center padding-xm text-red"
							:style="{ left: `${formItem.labelStyle.width}` }" v-show="formItem.error && errType === 'line'">
							<!-- <text class="cuIcon-info margin-right-xm"></text> -->
							{{formItem.error}}
						</view>
					</es-view>
				</radio-group>

				<checkbox-group :id="`formItem_`+formItem.model" class="block form-item-wrapper"
					:class="formItem.groupCls" @change="checkboxChange(formItem, $event)" :key="`check${formIndex}`"
					v-if="formItem.type === 'checkbox' && !formItem.hidden">
					<!-- 垂直排列 -->
					<template v-if="formItem.columnType === 'v'">
						<es-view class="cu-form-group" :class="formItem.wrapCls">
							<es-view class="title" :style="formItem.labelStyle" :cls="formItem.labelCls"
								v-if="formItem.showLabel">{{formItem.label}}
							</es-view>
						</es-view>
						<es-view class="cu-form-group" v-for="checkItem of formItem.items" :key="checkItem.value">
							<es-view class="title" :style="formItem.labelStyle" :cls="formItem.labelCls">{{checkItem.t}}
							</es-view>
							<!-- 自定义样式 -->
							<es-view style="position: relative;" :cls="formItem.wrapCls"
								:class="[checkItem.c ? formItem.selCls : formItem.noSelCls, checkItem.d ? 'disabled' : '']"
								v-if="formItem.custom === true">
								<v-template :template="formItem.slot"></v-template>
								<checkbox :disabled="checkItem.d" class="hide-radio" :checked="checkItem.c ?true:false"
									:value="checkItem.v"></checkbox>
							</es-view>

							<checkbox v-else :disabled="checkItem.d"
								:class="[checkItem.c?'checked':''].concat(formItem.cls)"
								:checked="checkItem.c ?true:false" :value="checkItem.v"></checkbox>
						</es-view>
					</template>
					<!-- 水平排列 -->
					<es-view class="cu-form-group" :cls="formItem.wrapCls" v-if="formItem.columnType === 'h'">
						<es-view class="title" :style="formItem.labelStyle" :cls="formItem.labelCls"
							v-if="formItem.showLabel">{{formItem.label}}
						</es-view>
						<view>
							<template v-for="checkItem of formItem.items">
								<es-view :cls="formItem.hCls" :key="checkItem.v">
									<!-- 自定义样式 -->
									<es-view style="position: relative;" :cls="formItem.wrapCls"
										:class="[checkItem.c ? formItem.selCls : formItem.noSelCls, checkItem.d ? 'disabled' : '']"
										v-if="formItem.custom === true">
										<v-template :template="formItem.slot"></v-template>
										<checkbox :disabled="checkItem.d" class="hide-radio"
											:checked="checkItem.c ?true:false" :value="checkItem.v"></checkbox>
									</es-view>

									<template v-else>
										<text>{{checkItem.t}}</text>
										<checkbox :disabled="checkItem.d"
											:class="[checkItem.c?'checked':''].concat(formItem.cls)"
											:checked="checkItem.c ?true:false" :value="checkItem.v"></checkbox>
									</template>
								</es-view>
							</template>
						</view>
						<view :id="`showError_${formItem.model}`" :class="{ hide: !formItem.error }" class="show-error flex align-center padding-xm text-red"
							:style="{ left: `${formItem.labelStyle.width}` }" v-show="formItem.error && errType === 'line'">
							<!-- <text class="cuIcon-info margin-right-xm"></text> -->
							{{formItem.error}}
						</view>
					</es-view>
				</checkbox-group>
				<!-- 图片上传处理 -->
				<es-view :id="`formItem_`+formItem.model" class="cu-form-group align-start form-item-wrapper"
					:cls="formItem.wrapCls" :key="formIndex" v-else-if="formItem.type === 'upload' && !formItem.hidden">
					<es-view class="title" :style="formItem.labelStyle" :cls="formItem.labelCls"
						v-if="formItem.showLabel">
						{{formItem.label}}
					</es-view>
					<view :class="[`grid col-${formItem.line} grid-square flex-sub`]">
						<view class="bg-img" v-for="(item,index) in formItem.valueMap" :class="formItem.imgCls"
							:key="index" @tap="previewImg(formItem, $event)" :data-url="item.value"
							:data-preurl="item.preValue">
							<image :src="item.preValue" mode="aspectFill"></image>
							<view class="cu-tag bg-red" :class="formItem.delCls" @tap.stop="delImg(formItem, $event)"
								:data-index="index" v-if="!item.showProgress">
								<text class='cuIcon-close icon'></text>
							</view>
							<!-- 上传百分比 -->
							<!-- mask模式 -->
							<view class="bg-mask flex justify-center align-center text-white mask" @click.stop
								v-if="formItem.showProgress && formItem.progressType === 'mask' && item.showProgress"
								:class="[formItem.progressCls]">
								<text>{{item.progress}}%</text>
							</view>
							<!-- bar模式 -->
							<view class="mask flex align-end text-center" :class="[formItem.progressCls]" @click.stop
								v-if="formItem.showProgress && formItem.progressType === 'bar' && item.showProgress">
								<view class="cu-progress radius striped active" :class="formItem.prog">
									<view class="bg-green" :style="`width: ${item.progress}%;`">{{item.progress}}%
									</view>
								</view>
							</view>
							<view class="img-error text-center text-white" @click.stop>{{item.error}}</view>
						</view>
						<view class="solids" :class="formItem.btnCls" @tap="chooseImage(formItem, $event)"
							v-if="!formItem.btnImg && formItem.preValue.length<formItem.maxLen">
							<text
								:class="['cuIcon-'+(formItem.btnIcon ? formItem.btnIcon : 'cameraadd'), 'icon']"></text>
						</view>
						<view class="bg-img" @tap="chooseImage(formItem, $event)" :class="formItem.btnCls"
							v-if="formItem.btnImg && formItem.preValue.length<formItem.maxLen">
							<image :src="formItem.btnImg" mode="aspectFill"></image>
						</view>
					</view>
					
					<view :id="`showError_${formItem.model}`" :class="{ hide: !formItem.error }" class="show-error flex align-center padding-xm text-red"
						:style="{ left: `${formItem.labelStyle.width}` }" v-show="formItem.error && errType === 'line'">
						<!-- <text class="cuIcon-info margin-right-xm"></text> -->
						{{formItem.error}}
					</view>
				</es-view>
				<es-view :id="`formItem_`+formItem.model" class="cu-form-group form-item-wrapper"
					:cls="formItem.wrapCls" :key="formIndex"
					v-else-if="!formItem.hidden && OTHER_TYPE.indexOf(formItem.type) === -1">
					<slot v-if="formItem.before" :name="`before:${formIndex}`" :item="formItem"></slot>
					<es-view class="title" :style="formItem.labelStyle" :cls="formItem.labelCls"
						v-if="formItem.showLabel">
						{{formItem.label}}
					</es-view>

					<!-- link 类型 action类型 -->
					<template v-if="formItem.type === 'link' || formItem.type === 'action'">
						<view @tap="linkClick(formItem, $event)" class="flex align-center flex-sub">
							<input style="pointer-events: none;" :class="formItem.cls" :maxlength="formItem.maxLen"
								:placeholder-style="formItem.holderStyle" :placeholder="formItem.holder" type="text"
								v-model="formItem.type === 'action' ? formItem.showVal : formValue[formItem.model]" disabled></input>
							<text class="cuIcon cuIcon-right"></text>
							<!-- <es-icon :icon="formItem.rightIcon ? formItem.rightIcon : 'right'"
								:style="'color: '+formItem.iconColor"></es-icon> -->
							<view class="icon right-icon gray"></view>
						</view>
					</template>
					<!-- picker处理 -->
					<template v-else-if="formItem.type === 'picker'">
						<!-- <picker @change="pickerChange(formItem, $event)" @columnchange="columnchange(formItem, $event)" :value="formValue[formItem.model]"
							:range="formItem.items" range-key="t" :mode="formItem.mode">
							<es-view class="picker" :cls="formItem.cls" @tap="pickerHandle(formItem, $event)">
								{{pickerShow(formItem)}}
							</es-view>
						</picker> -->
						<view class="flex align-center flex-sub justify-end"
							@tap="pickerHandle(formItem, $event)">
							<es-view class="picker" :cls="formItem.cls">
								{{pickerShow(formItem)}}
							</es-view>
							<!-- <es-icon :icon="formItem.rightIcon ? formItem.rightIcon : 'right'"
								:style="'color: '+formItem.iconColor"></es-icon> -->
							<view class="icon right-icon gray"></view>
						</view>

					</template>
					<template v-else>
						<!-- 文本 input -->
						<input :class="formItem.cls" :maxlength="formItem.maxLen" v-if="formItem.type === 'text'"
							:placeholder="formItem.holder" :disabled="formItem.disabled" type="text"
							:placeholder-style="formItem.holderStyle" v-model="formValue[formItem.model]"
							@input="inputChange(formItem, $event)"></input>
						<!-- 多行文本 -->
						<textarea :class="formItem.cls" v-else-if="formItem.type === 'textarea'"
							:placeholder-style="formItem.holderStyle" :maxlength="formItem.maxLen"
							v-model="formValue[formItem.model]" :disabled="formItem.disabled"
							:placeholder="formItem.holder" @input="inputChange(formItem, $event)"></textarea>
						<!-- 密码 -->
						<input :placeholder-style="formItem.holderStyle" :class="formItem.cls"
							:maxlength="formItem.maxLen" v-else-if="formItem.type === 'password'"
							:placeholder="formItem.holder" type="password" :disabled="formItem.disabled"
							v-model="formValue[formItem.model]" @input="inputChange(formItem, $event)"></input>
						<!-- number -->
						<input :placeholder-style="formItem.holderStyle" :class="formItem.cls"
							:maxlength="formItem.maxLen" v-else-if="formItem.type === 'number'"
							:placeholder="formItem.holder" :disabled="formItem.disabled" type="number"
							v-model="formValue[formItem.model]" @input="inputChange(formItem, $event)"></input>

						<!-- switch -->
						<view v-else-if="formItem.type === 'switch'" style="flex: 1;">
							<u-switch inactiveColor="#ddd" :activeColor="themeColor" :disabled="formItem.disabled"
								v-model="formValue[formItem.model]"
								:class="[formValue[formItem.model]?'checked':'', SWITCH_ICONS[formItem.iconType]].concat(formItem.cls)"
								@change="(value) => { switchChange(formItem, value) }"></u-switch>
						</view>
						<!-- 右边元素 -->
						<template v-if="formItem.right">
							<form-right :item="formItem"></form-right>
						</template>
					</template>
					<slot v-if="formItem.after" :name="`after:${formIndex}`" :item="formItem"></slot>

					<view :id="`showError_${formItem.model}`" :class="{ hide: !formItem.error }" class="show-error flex align-center padding-xm text-red"
						:style="{ left: `${formItem.labelStyle.width}` }" v-show="formItem.error && errType === 'line'">
						<!-- <text class="cuIcon-info margin-right-xm"></text> -->
						{{formItem.error}}
					</view>
				</es-view>
			</template>
		</template>

		<es-button v-if="submitButton && typeof submitButton === 'object'" :cls="['round', 'margin']"
			:icon="submitButton.icon" :loadingDisabledText="submitButton.loadingDisabledText"
			:round="submitButton.round" :loading="loading" :radius="submitButton.radius" @click="submit" theme>
			{{submitButton.text}}
		</es-button>

		<!-- type = action -->
		<u-action-sheet v-if="curAction" :actions="curAction.items" :title="curAction.title"
			:cancelText="curAction.cancelText" :show="actionShow" :closeOnClickAction="curAction.closeOnClickAction"
			:closeOnClickOverlay="curAction.closeOnClickOverlay" @close="closeAction" @select="selectAction">
		</u-action-sheet>

		<!-- type = picker -->
		<u-picker v-if="curPicker && DATE_TYPE.indexOf(curPicker.mode) === -1" :show="showPicker" ref="uPicker"
			:columns="pickerColumn" @cancel="cancelPicker" @close="closePicker"
			:closeOnClickOverlay="curPicker.closeOnClickOverlay" keyName="t"
			:defaultIndex="typeof formValue[curPicker.model] === 'number' ? [formValue[curPicker.model]] : formValue[curPicker.model]"
			@confirm="confirmPicker" @change="pickerChange(curPicker, $event)"></u-picker>

		<u-datetime-picker v-if="curPicker && DATE_TYPE.indexOf(curPicker.mode) !== -1" :show="showPicker"
			:value="formValue[curPicker.model]" ref="timePicker" @cancel="cancelPicker" @close="closePicker"
			:closeOnClickOverlay="curPicker.closeOnClickOverlay" @confirm="confirmPicker" v-bind="curPicker.rangeObj"
			:formatter="curPicker.formatter" :mode="curPicker.mode" @change="pickerChange(curPicker, $event)">
		</u-datetime-picker>
	</view>
</template>

<script>
	// form表单项类型：
	// **link: 链接
	// **text: 文本类型
	// **number: 数字文本类型
	// **password: 密码类型
	// **radio: 单选框
	// **checkbox: 复选框
	// **textarea: 多行文本框
	// **action: ActionSheet选项框
	// **picker: picker选项框
	// **upload: 图片上传
	// **hidden: 隐藏表单
	// **custom: 从中插入自定义内容

	import Vue from 'vue'
	import classSimple from '../mixins/classSimple'
	import FormRight from './form-right'

	export default {
		mixins: [classSimple],
		props: {
			// 左侧文字宽度
			labelWidth: {
				type: Number | String,
				default () {
					return ''
				}
			},
			// label对齐方式
			labelAlign: {
				type: String,
				default () {
					return 'left'
				}
			},
			// label样式类
			labelCls: {
				type: String | Array,
				default () {
					return ''
				}
			},
			// 表单配置
			config: {
				type: Array,
				default () {
					return []
				}
			},
			errType: {
				type: String,
				default () {
					return 'line'
				}
			}, // 错误提示方式 [line, 'toast', 'modal']
			submitButton: {
				type: Object | Boolean,
				default () {
					return {
						cls: [],
						text: '提交',
						icon: '',
						loadingDisabledText: '提交中...'
					}
				}
			},
			getHidden: { // 是否获取隐藏元素
				type: Boolean,
				default () {
					return false
				}
			}
		},
		data() {
			return {
				themeColor: '#58B6F8',
				form: null, // form配置
				formValue: {}, // 表单值
				// 内置switch-icon
				SWITCH_ICONS: {
					sex: 'switch-sex',
					check: '',
					no: 'no-icon'
				},
				OTHER_TYPE: ['upload', 'checkbox', 'radio', 'custom'], // 特殊处理的表单类型
				ITEMS_TYPE: ['action'], // 有items传入值和显示值不一样的类型
				DATE_TYPE: ['date', 'time', 'year-month',
				'datetime'], // type = picker 日期mode类型 参考uview  DatetimePicker选择器mode
				actionList: [], // action列表
				actionTitle: '', // action title
				actionShow: false, // 显示action
				showPicker: false, // 显示picker
				curAction: null,
				curPicker: null, // 当前picker
				loading: false, // 提交按钮置灰
				connIndexs: [], // 单独针对级联picker选择器做change事件处理（因为change事件在conn=true时必须要触发）
			}
		},
		computed: {
			// 动态生成columns
			pickerColumn() {
				// 使用concat生成一个新数组
				let items = this.curPicker.items.concat([])
				const newItems = items.concat([])
				// let value = this.formValue[this.curPicker.model]
				let value = this.connIndexs
				if (this.curPicker.conn) {
					let children = this.curPicker.children
					// 根据绑定值动态添加列的长度
					for (let [i, v] of value.entries()) {
						if (i !== 0) {
							items[i] = []
						}
					}

					// 第一列
					let step = 0 // 当前步数
					let first = newItems[value[0]]

					function setItems(item) {
						if (item[children] && item[children].length) {
							step++
							items[step] = item[children]
							setItems(item[children][value[step]])
						}
					}

					setItems(first)

					// 因为第一列为单个对象，所有需要重新赋值
					items[0] = newItems
				} else {
					// [{ t: '选项1', v: '1' }, { t: '选项2', v: '2' }]
					// ==============================================
					// [[{ t: '选项1', v: '1' }, { t: '选项2', v: '2' }]]
					// 对这种情况进行处理
					let isTwoArray = items.some(items => {
						return Array.isArray(items)
					});

					if (!isTwoArray) {
						items = [items]
					}
				}

				return items
			},
		},
		components: {
			FormRight,
			// 自定义渲染模板组件
			'v-template': {
				functional: true,
				props: {
					template: {
						type: String,
						default () {
							return ''
						}
					},
					data: {
						type: Object,
						default () {
							return {}
						}
					}
				},
				render: (h, ctx) => {
					return h('uni-view', {
						domProps: {
							innerHTML: ctx.props.template
						}
					})
				}
			},
		},
		created() {
			// 共用的默认配置
			this.default = {
				showLabel: true, // 是否展示label
				cls: [], // 额外的简写class
				labelCls: [], // label的class
				value: '', // 默认值
				verify: '-1%-1%-1', // 表单验证,
				error: '', // 错误提示
				labelStyle: {},
				maxLen: -1,
				disabled: false, // 是否禁用
				hidden: false, // 是否隐藏
				holderStyle: 'color: #ccc',
				init() {}, // 初始化回调(任何表单初始化值在此回调)
				change() {},
			} // form表单项的默认配置

			// 每个form表单项的选项配置
			this.formItemConfig = {
				text: {
					right: null, // 右边元素 { type: 'text', cls: [], text: '', click: null } { type: 'icon', size: [], color: '', name: '', click: null } { type: 'button', cls: [], text: '', click: null },
				},
				number: {
					right: null,
				},
				switch: {
					icon: '', // 如果是数组, 2个图标class; 如果是空或者是false, 不用显示图标; 如果是字符串, 内置图标
					color: '', // 选中颜色
					iconType: 'no' // 按钮类型
				},
				upload: {
					previewImg: true, // 上传后支持预览
					maxLen: 9, // 最多上传图片
					single: false, // 是否单图上传
					del: null, // 删除回调
					accept: '*', // 上传支持的格式
					size: '', // 限制文件大小
					showProgress: true, // 是否展示进度条
					progressType: 'bar', // 进度条模式  bar: 进度条， mask: 蒙层
					sq: true, // 是否为方形
					sizeType: ['original', 'compressed'],
					sourceType: ['album', 'camera'],
					line: 3, // 一行显示多少个
					btnImg: '', // 按钮渲染成图片，提供图片的src
					btnCls: [], // 按钮class
					btnIcon: '', // 上传按钮中间图标
					modal: false, // 删除是否有弹框
					preValue: undefined, // 预览图片数组
					onDel() {}, // 删除后的回调
					success() {}, // 上传成功回调
					fail() {}, // 上传失败
				}, // 图片上传
				radio: {
					custom: false, // 是否自定义样式
					columnType: 'h', // 默认水平排列
					groupCls: [], // radio-group样式
					items: [], // 选项列表
					selCls: 'sel', // 选中class（custom为true生效）
					noSelCls: 'no-sel', // 选中class（custom为true生效）
					slot: '', // 自定义模板内容（custom为true生效）
					hCls: [], // 水平排列class（columnType = 'h'生效）
				},
				checkbox: {
					custom: false, // 是否自定义样式
					columnType: 'h', // 默认水平排列
					groupCls: [], // check-group样式
					items: [], // 选项列表
					selCls: 'sel', // 选中class（custom为true生效）
					noSelCls: 'no-sel', // 选中class（custom为true生效）
					slot: '', // 自定义模板内容（custom为true生效）
					hCls: [], // 水平排列class（columnType = 'h'生效）
				},
				picker: {
					conn: false, // 是否级联(如果是级联，只能传入一维数组对象Array<Object>形式，Object中必须包含children属性)mode不为时间才生效
					children: 'children', // 默认子列的属性（conn为true生效）
					formatter: null, // 格式化规则函数(mode为日期时间格式才有效)
					mode: '', // date为日期选择，time为时间选择，year-month为年月选择, datetime日期时间 默认为空，选择器
					closeOnClickOverlay: true,
					range: [], // 限定最大最小日期(mode为日期时间格式才有效)
					items: [],
					click: function() {}, // 点击picker时触发事件
					confirm: function() {}, // 点击确定回调
				},
				action: {
					title: '', // action标题
					items: [], // action items
					cancelText: '取消', // 显示取消按钮
					closeOnClickAction: true, // 当点击某一项是否关闭
					closeOnClickOverlay: true, // 点击蒙层是否关闭
					itemClick: function() {}, // 菜单选项被点击
					click: function() {}
				}
			}

			// 遍历配置
			this.form = this.config.map(item => {
				// 针对upload组件处理preValue
				if (item.type === 'upload') {
					// 如果没传默认value值
					item.preValue = item.preValue || item.value || []

					item.valueMap = item.preValue.map((cItem, index) => {
						return {
							value: item.value[index],
							preValue: cItem,
							progress: 0, // 当前进度
							showProgress: false, // 是否展示进度条
						}
					})

				}
				// 处理items字段name属性问题
				if (item.type === 'action') {
					item.items = item.items.map(it => {
						return {
							name: it.t,
							t: it.t,
							v: it.v,
							disabled: it.d
						}
					})
				}

				// 选中值和获取值不一样的items处理
				if (this.ITEMS_TYPE.indexOf(item.type) !== -1) {
					// 展示值和获取值
					this.formItemConfig[item.type].showVal = ''
				}

				let _def = Object.assign({}, this.default, this.formItemConfig[item.type] || {}, item)

				// 把简写的cls全部转化成数组
				for (let _d in _def) {
					const d = _d.toLowerCase()
					if (d.indexOf('cls') !== -1) {
						if (typeof _def[_d] === 'string') {
							_def[_d] = [_def[_d]]
						}
					}
				}
				// 设置labelWidth
				if (_def.labelStyle.width) {
					if (typeof _def.labelStyle.width === 'string') {
						_def.labelStyle.width = _def.labelStyle.width
					} else if (typeof _def.labelStyle.width === 'number') {
						_def.labelStyle.width = _def.labelStyle.width + 'rpx'
					}
				} else {
					if (this.labelWidth) {
						if (typeof this.labelWidth === 'string') {
							_def.labelStyle.width = this.labelWidth
						} else if (typeof this.labelWidth === 'number') {
							_def.labelStyle.width = this.labelWidth + 'rpx'
						}
					}
				}
				_def.labelStyle.textAlign = this.labelAlign
				return _def
			})
			this._map()
		},
		methods: {
			// 设置某个表单项错误信息
			setError(model, error) {
				const formItem = this.formMap[model]
				if (!formItem) {
					return
				}
				formItem.error = error
			},
			setFormItem(model, prop, value) {
				const formItem = this.formMap[model]
				if (!formItem) {
					return
				}
				formItem[prop] = value
			},
			reset() {
				for (let model in this.formMap) {
					this.value(model, '')
				}
			},
			// 动态设置items值（只针对有items属性）
			setItems(model, items) {
				const formItem = this.formMap[model]
				if (!formItem) {
					return
				}
				formItem.items = items
			},
			/**
			 * 获取表单项值
			 * @param {Object} model 表单字段
			 * @param {Object} val 表单值
			 * 如果val没传则为获取值
			 */
			value(model, val) {
				const formItem = this.formMap[model]
				if (!formItem) {
					return
				}
				if (typeof val !== 'undefined') {
					if (formItem.type === 'checkbox') {
						// checkbox设置值特殊
						for (let [index, item] of formItem.items.entries()) {
							item.c = (val.indexOf(item.v) !== -1)
						}
					} else if (formItem.type === 'upload') {
						// 上传图片
						this.formValue[model] = []
						formItem.preValue = []
						for (let valItem of val) {
							this._setUpload(formItem, model, valItem)
						}

					} else if (formItem.type === 'action') {
						this._setAction(formItem, model, val)
					} else {
						this.formValue[model] = val
					}
				} else {
					const value = this.formValue[model]
					// picker特殊处理,picker为非日期类型的value值为索引
					if (formItem.type === 'picker' && this.DATE_TYPE.indexOf(formItem.mode) === -1) {
						return formItem.items[value] ? formItem.items[value].v : ''
					} else if (formItem.type === 'checkbox') {
						// checkbox单独处理
						const items = formItem.items.filter(item => item.c)
						return items.map(item => item.v)
					} else if (formItem.type === 'upload') {
						return formItem.valueMap.map(item => item.value)
					} else {
						return value
					}
				}
			},
			// 表单全部验证通过
			isVerify() {
				const modelMap = this.form.map(form => form.model)
				this.verify(modelMap)
				const error = this.form.filter(item => item.error !== '')
				if (error.length > 0) {
					// 验证不通过
					let selector = ''
					for (let form of this.form) {
						if (form.error) {
							selector = `#formItem_${form.model}`
							this.curError = form.error
							this.curErrorItem = form
							break
						}
					}
					this.$nextTick(() => {
						// const selector = `#formItem_${this.curErrorItem.model}`
						console.log(selector)
						uni.pageScrollTo({
							duration: 100,
							selector
						})
					})

					return false
				}

				return true
			},
			// 提供一个方法外部设置columns
			setColumn(formItem, index, data) {
				this.$nextTick(() => {
					const picker = this.$refs.uPicker
					picker.setColumnValues(index, data)
					formItem.items[index] = data
				})
			},
			confirmPicker(e) {
				this.showPicker = false
				const bool = this.curPicker.confirm(e, this)
				if (bool !== false) {
					this._setPicker(this.curPicker, e)
				}
			},
			closePicker() {
				this.cancelPicker()
			},
			cancelPicker() {
				this.showPicker = false
				if (this.pickerTimer) {
					clearTimeout(this.pickerTimer)
				}
				this.pickerTimer = setTimeout(() => {
					this.curPicker = null
				}, 400)
			},
			pickerHandle(formItem) {
				if (formItem.disabled) {
					return
				}
				this.curPicker = formItem
				this.showPicker = true
				this.connIndexs = this.formValue[formItem.model]
				this.$nextTick(() => {
					formItem.click(this)
				})
			},
			// picker值展示
			pickerShow(formItem) {
				let value = this.formValue[formItem.model]
				// datetime类型
				if (this.DATE_TYPE.indexOf(formItem.mode) != -1) {
					return value || formItem.holder
				} else {
					let items = formItem.items.concat([])
					const newItems = items.concat([])
					if (formItem.conn) {
						let children = formItem.children

						// 设置显示的值
						let step = 0 // 当前步数
						let first = newItems[value[0]]
						let arr = [first.t]

						function setItems(item) {
							if (item[children] && item[children].length) {
								step++
								const childItem = item[children][value[step]]
								arr.push(childItem.t)
								setItems(childItem)
							}
						}

						setItems(first)
						return arr.length ? arr.join(',') : formItem.holder
					} else {
						if (typeof value === 'number') {
							value = [value]
						}
						let itemText = []
						for (let [index, text] of Object.entries(value)) {
							const item = formItem.items[index][text] || formItem.items[text]
							if (item) {
								item && itemText.push(item.t)
							}
						}

						return itemText.length > 0 ? itemText.join(',') : formItem.holder
					}
				}
			},
			switchChange(formItem, e) {
				this.changeHandle(formItem, {
					detail: {
						value: e
					}
				})
			},
			radioChange(formItem, e) {
				this.formValue[formItem.model] = e.detail.value
				this.changeHandle(formItem, e)
			},
			changeHandle(formItem, e) {
				this._changeVerify(formItem)
				const bool = formItem.change(e.detail.value, this)
				if (bool !== false) this.formValue[formItem.model] = e.detail.value
			},
			inputChange(formItem, e) {
				this._changeVerify(formItem)
				formItem.change(e.detail.value, this)
			},
			checkboxChange(formItem, e) {
				var items = formItem.items,
					values = e.detail.value;
				for (var i = 0, lenI = items.length; i < lenI; ++i) {
					items[i].c = false;
					for (var j = 0, lenJ = values.length; j < lenJ; ++j) {
						if (items[i].v == values[j]) {
							items[i].c = true;
							break
						}
					}
				}

				this._changeVerify(formItem)
				const bool = formItem.change(values)
				if (bool !== false) this.value(formItem.model, values)
			},
			pickerChange(formItem, e) {
				const bool = formItem.change(e)
				if (bool !== false) this._setPicker(formItem, e)
				if (formItem.conn) {
					this.connIndexs = e.indexs
				}
			},
			linkClick(formItem, e) {
				if (formItem.disabled) {
					return
				}
				if (formItem.type === 'link') {
					formItem.click.call(formItem, this)
				} else if (formItem.type === 'action') {
					this.curAction = formItem
					this.actionShow = true
					formItem.click.call(formItem, this)
				}
			},
			selectAction(e) {
				this.formValue[this.curAction.model] = e.v
				this.curAction.showVal = e.name
				this._changeVerify(this.curAction)
			},
			closeAction() {
				this.actionShow = false
				// setTimeout(() => {
				// 	this.curAction = null
				// }, 2000)
			},
			chooseImage(formItem, e) {
				const that = this
				const len = formItem.single ? 1 : formItem.maxLen
				uni.chooseImage({
					count: len, // 最大数量
					sizeType: formItem.sizeType, //可以指定是原图还是压缩图，默认二者都有
					sourceType: formItem.sourceType, //从相册选择
					success: (res) => {
						let itemVal = this.formValue[formItem.model]
						if (formItem.preValue.length != 0) {
							formItem.preValue = formItem.preValue.concat(res.tempFilePaths)
						} else {
							formItem.preValue = res.tempFilePaths
						}

						let uploadSuccess = 0 // 上传成功数
						const tempLength = res.tempFilePaths.length

						for (let [index, temp] of res.tempFilePaths.entries()) {
							let obj = {
								value: '',
								preValue: res.tempFilePaths[index],
								progress: 0, // 当前进度
								showProgress: true, // 是否展示进度条
								error: ''
							}

							// 通过后台上传图片
							obj.task = that.$es.upload(temp, formItem.file ? formItem.file : 'file', function(
								result) {
								uploadSuccess++
								obj.value = result
								// 成功隐藏进度条
								obj.showProgress = false
								obj.error = ''
								if (uploadSuccess >= tempLength) {
									// 全部上传完
									formItem.success(result)
								}
							}, function(msg) {
								formItem.fail(msg)
								obj.showProgress = false
								obj.error = '上传失败'
								console.error(msg)
							})

							formItem.valueMap.push(obj)
						}

						console.log(formItem.valueMap)

						// 进度更新
						for (let val of formItem.valueMap) {
							if (val.task) {
								val.task.onProgressUpdate((res) => {
									val.progress = res.progress
								});
							}
						}
					}
				});
			},
			delImg(formItem, e) {
				const that = this
				const del = function() {
					const index = e.currentTarget.dataset.index
					const value = formItem.valueMap[index]
					// 同时删除value和preValue数据
					formItem.valueMap.splice(index, 1)
					formItem.preValue.splice(index, 1)
					formItem.onDel(index, value.value)
				}
				if (formItem.modal) {
					formItem.modal = typeof formItem.modal !== 'object' ? {} : formItem.modal
					uni.showModal({
						title: formItem.modal.title || '提示',
						content: formItem.modal.content || '你确定要删除该图片吗？',
						cancelText: formItem.modal.cancelText || '取消',
						confirmText: formItem.modal.confirmText || '确定',
						success: res => {
							if (res.confirm) {
								del.call(that)
							}
						}
					})
				} else {
					del.call(that)
				}
			},
			previewImg(formItem, e) {
				uni.previewImage({
					urls: formItem.preValue,
					current: e.currentTarget.dataset.preurl
				});
			},
			getFormData() {
				let obj = {}
				for (let form of this.form) {
					if (form.type !== 'link' && form.type !== 'custom') {
						if (!form.hidden || this.getHidden === true) obj[form.model] = this.value(form.model)
					}
				}

				return obj
			},
			setHidden(models = [], hidden = true) {
				for (let item of this.form) {
					if (models.indexOf(item.model) !== -1) {
						item.hidden = hidden
					}
				}
			},
			// 单个或多个表单验证，外部调用此方法
			verify(model) {
				if (typeof model === 'string') {
					model = [model]
				}
				let err = ''
				let data = {}
				for (let form of this.form) {
					if (model.indexOf(form.model) !== -1) {
						this._verify(form)
						if (form.error) {
							err = form.error
						} else {
							data[form.model] = this.value(form.model)
						}
					}
				}
				if (err === '') {
					return data
				}
				return false
			},
			// 外部调用的submit方法
			submit(e, setLoading) {
				if (this.isVerify()) {
					typeof setLoading === 'function' && setLoading(true)
					this.$emit('submit', this.getFormData(), setLoading)
				} else {
					if (this.errType === 'toast') {
						this.$es.toast(this.curError)
					} else if (this.errType === 'modal') {
						uni.showModal({
							title: '提示',
							content: this.curError,
							showCancel: false
						})
					}
					this.$emit('error', this.curErrorItem)
				}
			},
			// 获取最大小值范围
			_getDateRange(formItem) {
				const range = formItem.range
				if (formItem.mode === 'time') {
					let obj = {}
					const [d1, d2] = range
					// 时分
					if (d1) {
						const [h1, m1] = d1.split(':')
						obj.minHour = Number(h1)
						obj.minMinute = Number(m1)
					}
					if (d1) {
						const [h2, m2] = d2.split(':')
						obj.maxHour = Number(h2)
						obj.maxMinute = Number(m2)
					}

					return obj

				} else {
					let obj = {}
					const [d1, d2] = range
					if (d1) {
						let time = new Date(d1.replace(/-/g, '/')).getTime()
						obj.minDate = (typeof d1 === 'number' ? d1 : new Date(d1.replace(/-/g, '/')).getTime())
					}
					if (d2) {
						obj.maxDate = (typeof d2 === 'number' ? d2 : new Date(d2.replace(/-/g, '/')).getTime())
					}

					return obj
				}

				return null
			},
			_setPicker(formItem, e) {
				// 默认格式
				if (this.DATE_TYPE.indexOf(formItem.mode) !== -1) {
					const format = {
						date: 'yyyy-mm-dd',
						'year-month': 'yyyy-mm',
						time: '',
						datetime: 'yyyy-mm-dd hh:MM'
					}
					this.formValue[formItem.model] = format[e.mode] && typeof e.value === 'number' ? this.$u.timeFormat(e
						.value, format[e.mode]) : e.value
				} else {
					this.formValue[formItem.model] = e.indexs
				}
			},
			_setAction(formItem, model, val) {
				let item = formItem.items.find(it => it.v === val)
				if (item) {
					formItem.showVal = item.t
					this.formValue[model] = item.v
				}
			},
			_setUpload(formItem, model, valItem) {
				const that = this

				function pushMap([v, p]) {
					formItem.valueMap.push({
						value: v,
						preValue: p,
						progress: 0, // 当前进度
						showProgress: false, // 是否展示进度条
					})
					formItem.preValue.push(p)
					that.formValue[model].push(v)
				}
				if (uni.$u.test.array(valItem)) {
					const [v, p] = valItem
					pushMap(v, p)
				} else if (typeof valItem === 'string') {
					// 如果string，预览值和实际值一致
					pushMap(valItem, valItem)
				}
			},
			/**
			 * @param {Object} formItem
			 * 值改变后需要重新验证
			 */
			_changeVerify(formItem) {
				if (this.errType === 'line') {
					this.verify([formItem.model])
				}
			},
			/**
			 * 判断verify规则是否通过
			 */
			_verify(item) {
				item.error = this.$es.verify(item.verify, this.formValue[item.model])
			},
			_map() {
				// 遍历配置文件，把它变成map形式，键值为model属性
				// 注：有items属性默认值value值是items索引
				this.formMap = {}
				for (let form of this.form) {
					if (form.model) {
						this.formMap[form.model] = form
						this.$set(this.formValue, form.model, form.value)
						if (this.ITEMS_TYPE.indexOf(form.type) !== -1) {
							this._setAction(form, form.model, form.value)
						}
						// 时间格式
						if (this.DATE_TYPE.indexOf(form.mode) !== -1) {
							form.rangeObj = this._getDateRange(form)
						}
						// checkbox需要动态设置c属性
						if (form.type === 'checkbox') {
							for (let item of form.items) {
								this.$set(item, 'c', item.c === true ? item.c : false)
							}
						}
						form.init.call(form, this)
					}
				}
			}
		}
	}
</script>

<style lang="scss" scoped>
	.hide-radio {
		position: absolute;
		left: 0;
		right: 0;
		top: 0;
		bottom: 0;
		z-index: 9999;
		opacity: 0;
	}

	.mask {
		position: absolute;
		left: 0;
		right: 0;
		top: 0;
		bottom: 0;
		z-index: 9999;
		background-color: rgba($color: #000000, $alpha: .3);
		font-weight: bold;
	}

	.no-icon {

		&::after,
		&::before {
			display: none
		}
	}

	.show-error {
		position: absolute;
		height: 60rpx;
		line-height: 1;
		bottom: 10rpx;
		left: 0;
		background-color: #fff;
		padding: 0 30upx;
		font-size: 24rpx;
		line-height: 24rpx;
		height: 24rpx;

		text {
			margin-right: 10rpx;
			vertical-align: top;
		}

		&.hide {
			display: none;
		}
	}

	.img-error {
		display: flex;
		align-items: center;
		justify-content: center;
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		font-size: 24rpx;
		z-index: 999;
		background-color: rgba($color: #000000, $alpha: .5);
	}

	.cu-form-group {
		position: relative;
		padding: 0 34rpx;
		min-height: 114rpx;
		&.border-bottom {
			border-bottom: 1rpx solid #eee;
		}
		
		&.radio-group-wrap {
			.title {
				height: 114rpx;
				line-height: 114rpx;
			}
		}

		input {
			height: 60rpx;
			font-size: 28rpx;
		}

		textarea {
			height: 76rpx;
		}
	}

	.cu-form-group+.cu-form-group {
		border-color: #F6F6F6;
	}

	.cu-form-group .title {
		font-size: 28rpx;
	}

	.radio-item-wrap {
		display: flex;
		flex-wrap: wrap;
		flex: 1;
		min-height: 114rpx;
		align-items: center;
		>view {
			margin: 20rpx 0;
		}
	}

	.radio-item {
		display: flex;
		align-items: center;
		margin-right: 60rpx;

		.icon-circle {
			margin-right: 4rpx;
		}
	}
</style>
